package server

import (
	"aero-sched/pkg/config"
	"aero-sched/pkg/log"
	"context"
	"fmt"
	"net"
	"strconv"
	"time"
)

const (
	connReadTimeout       time.Duration = 10 * time.Second
	vhostReadWriteTimeout time.Duration = 30 * time.Second
)

// Service service
type Service struct {
	// Accept connections from client
	listener net.Listener
	// service context
	ctx context.Context
	// call cancel to stop service
	cancel context.CancelFunc
}

func NewService(cfg *config.ServerConfig) (*Service, error) {
	svr := &Service{}

	address := net.JoinHostPort(cfg.Addr, strconv.Itoa(cfg.Port))
	ln, err := net.Listen("tcp", address)
	if err != nil {
		return nil, fmt.Errorf("create server listener error, %v", err)
	}
	log.Infof("aero sched listen on %s", address)

	svr.listener = ln

	return svr, nil
}

func (svr *Service) Run(ctx context.Context) {
	ctx, cancel := context.WithCancel(ctx)
	svr.ctx = ctx
	svr.cancel = cancel

	go svr.HandleListener(svr.listener)

	<-svr.ctx.Done()
	// service context may not be canceled by svr.Close(), we should call it here to release resources
	if svr.listener != nil {
		svr.Close()
	}
}

func (svr *Service) HandleListener(ln net.Listener) {
	// Listen for incoming connections from client.
	for {
		accept, err := ln.Accept()
		if err != nil {
			log.Warnf("Listener for incoming connections from client closed")
			return
		}

		ctx := context.Background()

		go func(ctx context.Context, conn net.Conn) {
			svr.handleConnection(ctx, conn)
		}(ctx, accept)

	}
}

func (svr *Service) Close() {
	if svr.cancel != nil {
		svr.cancel()
	}
}

func (svr *Service) handleConnection(ctx context.Context, conn net.Conn) {

}
